package jdbcmapper;

import java.sql.Connection;
import java.util.*;

import lotus.domino.*;
/**
 * <p>Title: JDBC Mapper</p>
 *
 * <p>Description: Libraries to copy documents form Lotus Notes to jdbc
 * table</p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: The Salvation ARmy</p>
 *
 * @author Ansel Robateau
 * @version 1.1
 */
public class Table extends NotesDoc{
    public static final String SQLDATABASE = "SQLDatabase";
    public static final String SQLTABLE = "SQLTable";
    public static final String bool_PRIMARYKEY = "Primarykey";
    public static final String DESCRIPTION = "Description";
    public static final String int_PRIORITY = "Priority";
    public static final String date_ERROR = "Error";
    public static final String ErrorMSG = "ErrorMsg";
    public static final String bool_MULTIFORM = "MultiForm";
    public static final String bool_NODELETE = "NoDelete";
    public static final String ALLDOCUMENTSBYDATE = "(All Documents by Date and Form)";
    private SQLDB m_parent;
	private String m_dateref;
	private String m_textlimit;
    public Table(Session session,Document doc) {
        super(session,doc);
    }
    public FieldMap getFirstFieldMap(){
        return (FieldMap)this.getFirst();
    }
    public FieldMap getNextFieldMap(){
        return (FieldMap)this.getNext();
    }
    public SQLDB getParent(){
        return this.m_parent;
    }
    /**
     * LoadMapping
     *
     * @param map FieldMap
     */
    @SuppressWarnings("unchecked")
	public void LoadMapping(SQLDB parent,FieldMap map) throws Exception {
        this.m_parent = parent;
        //View view = this.getDocument().getParentDatabase().getView("(FieldMaps by Notes Database)");
        Vector<String> keys = new Vector<String>();
        keys.add(map.getString(FieldMap.NOTESDATABASE));
        keys.add(map.getString(FieldMap.NOTESFORM));
        keys.add(map.getString(FieldMap.SQLDATABASE));
        keys.add(map.getString(FieldMap.SQLTABLE));
        //ViewEntryCollection vc = view.getAllEntriesByKey(keys);
        //ViewEntry entry = vc.getFirstEntry();
        String str = "Form = \"Field Map\" & "+map.NOTESDATABASE+" = \""+
                     map.getString(map.NOTESDATABASE)+"\" & "+
                     map.NOTESFORM+" = \"" + map.getString(map.NOTESFORM)+"\" & "+
                     map.SQLDATABASE+" = \"" + map.getString(map.SQLDATABASE)+"\" & "+
                     map.SQLTABLE+" = \"" + map.getString(map.SQLTABLE)+"\"";
        //System.out.println(str);
        this.getM_log().add(str);
        DocumentCollection col = this.getDocument().getParentDatabase().search(str);
        //System.out.println("Documents found = " + col.getCount());
        this.getM_log().add("Documents found = " + col.getCount());
        Document doc = col.getFirstDocument();
        while(doc != null){
            //doc = entry.getDocument();
            FieldMap fm = new FieldMap(this.getSession(),doc);
            fm.setParent(this);
            this.m_subs.add(fm);
            //entry = vc.getNextEntry();
            doc = col.getNextDocument(doc);
        }
    }

    /**
     * ExportDocuments
     */
    @SuppressWarnings("unchecked")
	public void ExportDocuments() throws Exception {
        SQLDB dbcon = this.getParent();

        NotesForm nform = dbcon.getParent();
        Connection con = dbcon.getConnection();
        if(con == null){
            System.out.println("jdbc connection failed");
            this.getM_log().add("jdbc connection failed");
            this.createLogEntry(true);
            return;
        }
        Vector<FieldMap> primarykeys = this.getPrimaryKeys();
        if(this.getBoolean(Table.bool_PRIMARYKEY) == true){
            if(primarykeys.size() == 0){
                System.out.println("Cannot save.  Primary keys required!");
                this.getM_log().add("Cannot save.  Primary keys required!");
                this.createLogEntry(true);
                return;
            }
        }
        if(this.getBoolean(Table.bool_MULTIFORM) == true){
            if(this.hasFormValue() == false){
                System.out.println("Cannot save.  This is a multiform table and a form field is required!");
                this.getM_log().add("Cannot save.  This is a multiform table and a form field is required!");
                this.createLogEntry(true);
                return;
            }
        }
        NotesDB notesdb = this.getParent().getParent().getParent();
        //this.getM_log().removeAllElements();
        try{
            // Connect to the notes database
            String server = notesdb.getString(NotesDB.SERVER);
            String dbfilename = notesdb.getString(NotesDB.FILENAME);
            java.util.Date lastaccessed = nform.getDate(NotesForm.date_LASTACCESSED);
            Database db = notesdb.getSession().getDatabase(server, dbfilename);
            System.out.println();
            System.out.println(db.getTitle());
            // Retrieve documents
            NotesForm form = this.getParent().getParent();
            String formname = form.getName();
            DateTime dt = null;
            if (lastaccessed != null) {
                dt = this.getSession().createDateTime(lastaccessed);
            }
            Date now = new java.util.Date();
            String str = "Form = \"" + formname + "\"";
            System.out.println(str);
            this.getM_log().add(str);
            if(dt != null){
                this.getM_log().add("Last Accessed: " + dt.getDateOnly() +
                                    " " + dt.getTimeOnly());
                System.out.println("Last Accessed: " + dt.getDateOnly() +
                		            " " + dt.getTimeOnly());
            }
            /****************************************
             * Use the view instead of a full search
             * 10/16/2007 Ansel Robateau
             ****************************************/
            //View view = db.getView(ALLDOCUMENTSBYDATE);
            //ViewEntryCollection vcol = view.getAllEntriesByKey(formname.toLowerCase());
            //ViewEntry entry = vcol.getFirstEntry();
            if(dt!=null){
            	dt.adjustMinute(-1);
            }
            DocumentCollection col = db.search(str,dt);
            System.out.println("Documents found = " + col.getCount());
            this.getM_log().add("Documents found = " + col.getCount());
            // Copy the documents to SQLRecords
            //Document doc = entry.getDocument();
            Document doc = col.getFirstDocument();
            int i = 1;
            int documentcount = 0;
            boolean found = false;
            if(dt != null && doc != null){
            }
            while (doc != null) {
            	String currformname = doc.getItemValueString("Form");
            	if(currformname.toLowerCase().equals(formname.toLowerCase())){
            		Vector<String> log = this.getM_log();
            		SQLRecord record = new SQLRecord(this.getString(Table.SQLTABLE),
            				con,log);
            		record.setPrimaryKeys(primarykeys);
            		record = this.mapfields(record, doc);
            		try{
            			record.save();
            			System.out.print(".");
            		}catch(Exception e){
            			e.printStackTrace();
            			throw e;
            		}
            		documentcount ++;
            		found = true;
            		if(i % 20 == 0){
            			System.out.println();
            		}
            	}
            	//entry = vcol.getNextEntry();
                //if(entry != null){
                //	doc = entry.getDocument();
                //	if(dt != null){
                //    	after = lastaccessed.before(doc.getLastModified().toJavaDate());
                //    }
                //}else{
                //	doc = null;
                //}
                doc = col.getNextDocument(doc);
                i++;
            }
            if(documentcount > 0) //System.out.println();
            //System.out.print("There were "+documentcount+" documents processed");
            //System.out.println();
            // Delete documents that have been removed from lotus notes
            if(this.getBoolean(Table.bool_NODELETE) == false){
                DeleteManager dm = new DeleteManager(this.getParent().
                        getConnection(),
                        this.getString(Table.SQLTABLE),
                        this.getPrimaryKeys());
                dm.removeDeletedDocuments(this);
            }

            if(found){
                nform.setDateTime(NotesDB.date_LASTACCESSED, now);
                nform.save();
            }
            this.getDocument().removeItem(Table.ErrorMSG);
            this.getDocument().removeItem(Table.date_ERROR);
            this.save();
            //Create log entry
            this.createLogEntry(false);
            //this.getM_log().removeAllElements();
        }catch(Exception e){
                // Save the java error stack trace
        		//System.out.println();
        		//System.out.println("Error: "+e.getMessage());
                java.io.CharArrayWriter cw = new java.io.CharArrayWriter();
                java.io.PrintWriter pw = new java.io.PrintWriter(cw);
                e.printStackTrace(pw);
                Vector<Object> lines = com.robaone.util.Strmanip.split('\n',cw.toString());
				this.setDateTime(Table.date_ERROR,new Date());
                this.getDocument().removeItem(Table.ErrorMSG);
                RichTextItem errormsg = this.getDocument().createRichTextItem(Table.ErrorMSG);
                for(int i = 0; i < lines.size();i++){
                    if(i > 0){
                        errormsg.addNewLine();
                    }
                    errormsg.appendText(lines.get(i).toString());
                    this.getM_log().add((String) lines.get(i));
                }
                //Create log entry
                this.createLogEntry(true);
                /*
                Document logdoc = this.getDocument().getParentDatabase().createDocument();
                NotesDoc log = new NotesDoc(this.getSession(),logdoc);
                log.getDocument().appendItemValue("Form","Log Entry");
                log.setDateTime("LogDate",new java.util.Date());
                log.getDocument().appendItemValue("SQLDatabase",dbcon.getString(dbcon.SQLDATABASE));
                log.getDocument().appendItemValue("SQLTable",this.getString(this.SQLTABLE));
                log.getDocument().appendItemValue("Error","Yes");
                RichTextItem body = log.getDocument().createRichTextItem("Body");
                for(int i = 0; i < this.getM_log().size() && i < 1000;i++){
                    if(i > 0){
                        body.addNewLine();
                    }
                    body.appendText(this.getM_log().get(i).toString());
                }
                body.addNewLine(3);
                */
                for(int i = 0; i < lines.size();i++){
                    if(i > 0){
                        errormsg.addNewLine();
                        //body.addNewLine();
                    }
                    errormsg.appendText(lines.get(i).toString());
                    //body.appendText(lines.get(i).toString());
                }

                this.save();
                //log.save();
        }
    }

    /**
     * hasFormValue
     *
     * @return boolean
     */
    public boolean hasFormValue() throws Exception {
        boolean hasformval = false;
        FieldMap field = this.getFirstFieldMap();
        while(field!=null){
            String nfieldname = field.getString(FieldMap.NOTESFIELDNAME);
            if(nfieldname != null && nfieldname.toLowerCase().equals("form")){
                hasformval = true;
            }
            field = this.getNextFieldMap();
        }
        return hasformval;
    }

    /**
     * createLogEntry
     */
    public void createLogEntry(boolean error) throws Exception{
        /*
        SQLDB dbcon = this.getParent();
        System.out.println("Creating Log Entry");
        Document logdoc = this.getDocument().getParentDatabase().createDocument();
        NotesDoc log = new NotesDoc(this.getSession(),logdoc);
        log.getDocument().appendItemValue("Form","Log Entry");
        log.setDateTime("LogDate",new java.util.Date());
        log.getDocument().appendItemValue("SQLDatabase",dbcon.getString(dbcon.SQLDATABASE));
        log.getDocument().appendItemValue("SQLTable",this.getString(this.SQLTABLE));
        if(error){
            log.getDocument().appendItemValue("Error", "Yes");
        }
        RichTextItem body = log.getDocument().createRichTextItem("Body");
        for(int i = 0; i < this.getM_log().size() && i < 1000;i++){
            if(i > 0){
                body.addNewLine();
            }
            body.appendText(this.getM_log().get(i).toString());
        }
        log.save();
        */
    }

    /**
     * mapfields
     *
     * @param record SQLRecord
     * @param doc Document
     * @return SQLRecord
     */
    @SuppressWarnings("unchecked")
	public SQLRecord mapfields(SQLRecord record, Document doc)throws Exception {
        // field represents the field mapping for each individual field
        // to the sql field
        FieldMap field = this.getFirstFieldMap();
        // Ndoc represents the current document being syncronized
        NotesDoc ndoc = new NotesDoc(this.getSession(),doc);
        while(field != null){
            String notesfieldname = field.getString(FieldMap.NOTESFIELDNAME);
            String notesfieldtype = field.getString(FieldMap.NOTESFIELDTYPE);
            String sqlfieldname = field.getString(FieldMap.SQLFIELDNAME);
            String sqlfieldtype = field.getString(FieldMap.SQLFIELDTYPE);
            String delimiter = field.getString(FieldMap.SPLITDELIMITER);
            String word = field.getString(FieldMap.WORD);
            this.m_dateref = field.getString(FieldMap.DATEREF);
            this.m_textlimit = field.getString(FieldMap.SQLLENGTH);
            boolean multivalue = field.getBoolean(FieldMap.bool_MULTIVALUE);

            if(multivalue == false){
                // Use the mapping information to save the value of the Notes
                // field into the sql field.
                if(notesfieldtype.equals(FieldMap.type_SPLIT)){
                    this.setfieldvalues(notesfieldname,notesfieldtype,sqlfieldname,
                            sqlfieldtype,ndoc,record,
                            field.getDocument().getItemValue(FieldMap.SQLFIELDNAMES),
                            delimiter,Integer.parseInt(word));
                }else{
                    this.setfieldvalues(notesfieldname, notesfieldtype,
                                        sqlfieldname,
                                        sqlfieldtype, ndoc, record,
                                        field.
                                        getDocument().getItemValue(FieldMap.
                            SQLFIELDNAMES));
                }
            }else{
                // Use the mapping information to save the values of the
                // field into a separate table which is linked to the
                // primary table using the primary keys.
                this.mapmutlivaluefields(ndoc,field);
            }
            field = this.getNextFieldMap();
        }
        return record;
    }
    /***********
     * This method will translate the Notes field into an sql field type
     * and value and save it into the SQLRecord class so that it can
     * be written to the sql table upon evoking the save() method.
     */
    protected void setfieldvalues(String notesfieldname,
                                  String notesfieldtype,
                                  String sqlfieldname,
                                  String sqlfieldtype,
                                  NotesDoc ndoc,
                                  SQLRecord record,
                                  Vector<Object> SQLFieldnames) throws Exception {
        this.setfieldvalues(notesfieldname,notesfieldtype,sqlfieldname,
                            sqlfieldtype,ndoc,record,SQLFieldnames,null,0);
    }
    @SuppressWarnings("unchecked")
	protected void setfieldvalues(String notesfieldname,
                                  String notesfieldtype,
                                  String sqlfieldname,
                                  String sqlfieldtype,
                                  NotesDoc ndoc,
                                  SQLRecord record,
                                  Vector<Object> SQLFieldnames,
                                  String delimiter,
                                  int word) throws Exception {
        if (notesfieldtype.equals(FieldMap.type_TEXT)) {
            String val = ndoc.getString(notesfieldname);
            if(this.m_textlimit != null && this.m_textlimit.length() > 0 && sqlfieldtype.equalsIgnoreCase("text")){
            	try{
            		int length = Integer.parseInt(this.m_textlimit);
            		if(val != null){
            			val = val.substring(0,length);
            		}
            	}catch(Exception e){}
            }
            record.setField(sqlfieldname, val, sqlfieldtype);
        } else if (notesfieldtype.equals(FieldMap.type_DATE)) {
            Date d = ndoc.getDate(notesfieldname);
            record.setField(sqlfieldname, d, sqlfieldtype);
        }else if(notesfieldtype.equals(FieldMap.type_TIME)){
        	String time = "";
        	try{
        		Date dtime = ndoc.getDate(notesfieldname);
        		Calendar cal = Calendar.getInstance();
        		cal.setTime(dtime);
        		time = cal.get(Calendar.HOUR)+"";
        		time += ":"+ ((cal.get(Calendar.MINUTE)+"").length() == 1 ? "0"+cal.get(Calendar.MINUTE) : cal.get(Calendar.MINUTE)+"");
        		if(cal.get(Calendar.AM_PM) == Calendar.AM){
        			time += " AM";
        		}else{
        			time += " PM";
        		}
        	}catch(Exception e){
        		time = ndoc.getString(notesfieldname);
        	}
        	if(this.m_dateref != null && this.m_dateref.length() > 0 && sqlfieldtype.equalsIgnoreCase("datetime")
        			&& time != null && time.length() > 0){
        		Vector<Object> tokens = com.robaone.util.Strmanip.split(':', time);
        		Date d = ndoc.getDate(this.m_dateref);
        		Calendar cal = Calendar.getInstance();
        		cal.setTime(d);
        		Calendar timeval = Calendar.getInstance();
        		int year,month,date,hour,minute;
        		year = cal.get(Calendar.YEAR);
        		month = cal.get(Calendar.MONTH);
        		date = cal.get(Calendar.DATE);
        		hour = Integer.parseInt(tokens.get(0).toString());
        		if(time.endsWith("PM")){
        			hour += 12;
        		}
        		minute = Integer.parseInt(tokens.get(1).toString().substring(0,2));
        		timeval.set(year, month,date,hour,minute,0);
        		record.setField(sqlfieldname, timeval.getTime(), sqlfieldtype);
        	}
        }else if (notesfieldtype.equals(FieldMap.type_DOUBLE)) {
            Double d = ndoc.getDouble(notesfieldname);
            record.setField(sqlfieldname, d, sqlfieldtype);
        } else if (notesfieldtype.equals(FieldMap.type_INT)) {
            Integer val = ndoc.getInteger(notesfieldname);
            record.setField(sqlfieldname, val, sqlfieldtype);
        } else if (notesfieldtype.equals(FieldMap.type_UID)) {
            String uid = ndoc.getUID();
            record.setField(sqlfieldname, uid, sqlfieldtype);
        } else if (notesfieldtype.equals(FieldMap.type_PARENTUID)){
        	String uid = ndoc.getParentUID();
        	record.setField(sqlfieldname, uid, sqlfieldtype);
        } else if (notesfieldtype.equals(FieldMap.type_NAME)) {
            String name = ndoc.getString(notesfieldname);
            Name nname = this.getSession().createName(name);
            record.setField(sqlfieldname, nname.getCommon(), sqlfieldtype);
        } else if (notesfieldtype.equals(FieldMap.type_BOOLEANLIST)) {
            Vector<Object> values = ndoc.getDocument().getItemValue(notesfieldname);
            Hashtable<String, Object> booleanfields = new Hashtable<String, Object>();
            Vector<Object> v = SQLFieldnames;
            for (int i = 0; i < v.size(); i++) {
                String val = com.robaone.util.Strmanip.replacechar(v.get(i).
                        toString(), ' ', '_').toLowerCase();
                /**********
                 * Accomodate a new specification
                 * The boolean value can now specify the sql fieldname with the following
                 * format:  fieldvalue:sqlfieldname
                 */
                String[] booleanvalue_field_map = v.get(i).toString().split(":");
                if(booleanvalue_field_map.length > 1){
                	val = booleanvalue_field_map[1];
                }
                if (sqlfieldtype.equals(FieldMap.type_INT) || sqlfieldtype.equals(FieldMap.type_BOOLEAN)) {
                    Integer bval = new Integer(0);
                    booleanfields.put(val, bval);
                } else if (sqlfieldtype.equals(FieldMap.type_TEXT)) {
                    String bval = new String("No");
                    booleanfields.put(val, bval);
                } else if (sqlfieldtype.equals(FieldMap.type_DOUBLE)) {
                    Double bval = new Double(0);
                    booleanfields.put(val, bval);
                } 
            }
            for (int i = 0; i < values.size(); i++) {
                Object val = values.get(i);
                String strval = com.robaone.util.Strmanip.replacechar(val.toString(),
                        ' ', '_').toLowerCase();
                /**********
                 * Accomodate a new specification
                 * The boolean value can now specify the sql fieldname with the following
                 * format:  fieldvalue:sqlfieldname
                 */
                String[] booleanvalue_field_map = val.toString().split(":");
                if(booleanvalue_field_map.length > 1){
                	strval = booleanvalue_field_map[1];
                }
                val = booleanfields.get(strval);
                if (val != null) {
                    if (val instanceof Integer) {
                        val = new Integer(1);
                        booleanfields.put(strval, val);
                    } else if (val instanceof Double) {
                        val = new Double(1);
                        booleanfields.put(strval, val);
                    } else if (val instanceof String) {
                        val = new String("Yes");
                        booleanfields.put(strval, val);
                    }
                }
            }
            // Save the values to the sql fields
            Enumeration<String> keys = booleanfields.keys();
            while (keys.hasMoreElements()) {
                String key = keys.nextElement().toString();
                record.setField(key, booleanfields.get(key), sqlfieldtype);
            }
        } else if (notesfieldtype.equals(FieldMap.type_SPLIT)) {
                String value = this.getWord(ndoc.getString(notesfieldname),delimiter,word);
                record.setField(sqlfieldname, value, sqlfieldtype);
        } else if (notesfieldtype.equals(FieldMap.type_ATTACHMENT)){
        	Item item = ndoc.getDocument().getFirstItem(notesfieldname);
			try{
				RichTextItem rtitem = (RichTextItem)item;
				RichTextNavigator navigator = rtitem.createNavigator();
				boolean found = navigator.findFirstElement(RichTextItem.RTELEM_TYPE_FILEATTACHMENT);
				if(found){
					Base bitem = navigator.getFirstElement(RichTextItem.RTELEM_TYPE_FILEATTACHMENT);
					if(bitem instanceof EmbeddedObject){
						EmbeddedObject o = (EmbeddedObject)bitem;
						record.setField(sqlfieldname, o, sqlfieldtype);
					}
				}else{
					RichTextNavigator rtnav = rtitem.createNavigator();
				      System.out.println("Number of doc links = " +
				        rtnav.findFirstElement(RichTextItem.RTELEM_TYPE_DOCLINK));
				      System.out.println("Number of file attachments = " +
				        rtnav.findFirstElement(RichTextItem.RTELEM_TYPE_FILEATTACHMENT));
				      System.out.println("Number of OLE objects = " +
				        rtnav.findFirstElement(RichTextItem.RTELEM_TYPE_OLE));
				      System.out.println("Number of sections = " +
				        rtnav.findFirstElement(RichTextItem.RTELEM_TYPE_SECTION));
				      System.out.println("Number of tables = " +
				        rtnav.findFirstElement(RichTextItem.RTELEM_TYPE_TABLE));
				      System.out.println("Number of  table cells = " +
				        rtnav.findFirstElement(RichTextItem.RTELEM_TYPE_TABLECELL));
				      System.out.println("Number of text paragraphs = " +
				        rtnav.findFirstElement(RichTextItem.RTELEM_TYPE_TEXTPARAGRAPH));
				      System.out.println("Number of text runs = " +
				        rtnav.findFirstElement(RichTextItem.RTELEM_TYPE_TEXTRUN));
				}
				if(found == false){
					record.setField(sqlfieldname, null, sqlfieldtype);
				}
			}catch(Exception e){
				throw e;
			}
        }


    }
    /**
     * mapmutlivaluefields
     *
     * @param ndoc NotesDoc
     * @param field FieldMap
     */
    @SuppressWarnings("unchecked")
	protected void mapmutlivaluefields(NotesDoc ndoc, FieldMap field) throws Exception {
        String notesfieldname = field.getString(FieldMap.NOTESFIELDNAME);
        String notesfieldtype = field.getString(FieldMap.NOTESFIELDTYPE);
        String sqlfieldname = field.getString(FieldMap.SQLFIELDNAME);
        String sqlfieldtype = field.getString(FieldMap.SQLFIELDTYPE);
        String delimiter = field.getString(FieldMap.SPLITDELIMITER);
        String word = field.getString(FieldMap.WORD);
        String sqlmultivaluetablename = field.getString(FieldMap.SQLMULTIVALUETABLENAME);
        SQLRecord newrecord = new SQLRecord(sqlmultivaluetablename,
                                      this.getParent().getConnection(),
                                      this.getM_log());
        Vector<Object> values = ndoc.getDocument().getItemValue(notesfieldname);
        try{
            Vector<FieldMap> primarykeys = this.getPrimaryKeys();
            for(int j = 0; j < primarykeys.size();j++){
                FieldMap fm = primarykeys.get(j);
                if(fm.getString(FieldMap.NOTESFIELDTYPE).equals(FieldMap.type_SPLIT)){
                    this.setfieldvalues(fm.getString(FieldMap.NOTESFIELDNAME),
                            fm.getString(FieldMap.NOTESFIELDTYPE),
                            fm.getString(FieldMap.SQLFIELDNAME),
                            fm.getString(FieldMap.SQLFIELDTYPE),ndoc,
                            newrecord,null,fm.getString(FieldMap.SPLITDELIMITER),
                            Integer.parseInt(fm.getString(FieldMap.WORD)));
                }else{
                    this.setfieldvalues(fm.getString(FieldMap.NOTESFIELDNAME),
                                        fm.getString(FieldMap.NOTESFIELDTYPE),
                                        fm.getString(FieldMap.SQLFIELDNAME),
                                        fm.getString(FieldMap.SQLFIELDTYPE),
                                        ndoc, newrecord, null);
                }
            }
            newrecord.remove_keys(this.getPrimaryKeys());
        }catch(Exception e){
            e.printStackTrace();
            throw e;
        }
        for(int i = 0; i < values.size();i++){
            newrecord = new SQLRecord(sqlmultivaluetablename,
                                      this.getParent().getConnection(),
                                      this.getM_log());
            //newrecord.setPrimaryKeys(this.getPrimaryKeys());
            Vector<FieldMap> primarykeys = this.getPrimaryKeys();
            for(int j = 0; j < primarykeys.size();j++){
                FieldMap fm = primarykeys.get(j);
                if(fm.getString(FieldMap.NOTESFIELDTYPE).equals(FieldMap.type_SPLIT)){
                    this.setfieldvalues(fm.getString(FieldMap.NOTESFIELDNAME),
                                        fm.getString(FieldMap.NOTESFIELDTYPE),
                                        fm.getString(FieldMap.SQLFIELDNAME),
                                        fm.getString(FieldMap.SQLFIELDTYPE),
                                        ndoc, newrecord, null,
                                        fm.getString(FieldMap.SPLITDELIMITER),
                                        Integer.parseInt(fm.getString(FieldMap.WORD)));
                }else{
                    this.setfieldvalues(fm.getString(FieldMap.NOTESFIELDNAME),
                                        fm.getString(FieldMap.NOTESFIELDTYPE),
                                        fm.getString(FieldMap.SQLFIELDNAME),
                                        fm.getString(FieldMap.SQLFIELDTYPE),
                                        ndoc, newrecord, null);

                }
            }
            Object oval = values.get(i);
            if (notesfieldtype.equals(FieldMap.type_TEXT)) {
            	String val = oval.toString();
                if(this.m_textlimit != null){
                	if(this.m_textlimit.length() > 0 && sqlfieldtype.equalsIgnoreCase("text")){
                
                	try{
                		int length = Integer.parseInt(this.m_textlimit);
                		if(val != null){
                			val = val.substring(0,length);
                		}
                	}catch(Exception e){}
                	}
                }
                newrecord.setField(sqlfieldname, val, sqlfieldtype);
            } else if (notesfieldtype.equals(FieldMap.type_DATE)) {
                Date d = ((DateTime)oval).toJavaDate();
                newrecord.setField(sqlfieldname, d, sqlfieldtype);
            } else if (notesfieldtype.equals(FieldMap.type_DOUBLE)) {
                Double d = new Double(oval.toString());
                newrecord.setField(sqlfieldname, d, sqlfieldtype);
            } else if (notesfieldtype.equals(FieldMap.type_INT)) {
                Integer val = new Integer(oval.toString());
                newrecord.setField(sqlfieldname, val, sqlfieldtype);
            } else if (notesfieldtype.equals(FieldMap.type_NAME)) {
                String name = oval.toString();
                Name nname = this.getSession().createName(name);
                newrecord.setField(sqlfieldname, nname.getCommon(), sqlfieldtype);
            } else if (notesfieldtype.equals(FieldMap.type_SPLIT)) {
                String value = this.getWord(oval.toString(),delimiter,word);
                newrecord.setField(sqlfieldname, value, sqlfieldtype);
            }
            newrecord.save();
        }

    }

    /**
     * getWord
     *
     * @param string String
     * @param delimiter String
     * @param word String
     * @return String
     */
    protected String getWord(String string, String delimiter, String word) {
        try{
            int i = Integer.parseInt(word);
            return this.getWord(string,delimiter,i);
        }catch(Exception e){
            return null;
        }
    }
    @SuppressWarnings("unchecked")
	protected String getWord(String string, String delimiter, int word) {
        try{
        	Vector tokens = com.robaone.util.Strmanip.split(delimiter.charAt(0),string);
            int i = word-1;
            return tokens.get(i).toString();
        }catch(Exception e){
            return null;
        }
    }


    /**
     * getPrimaryKeys
     *
     * @return Vector
     */
    public Vector<FieldMap> getPrimaryKeys() throws Exception {
        Vector<FieldMap> retval = new Vector<FieldMap>();
        int savedindex = this.index;
        FieldMap field = this.getFirstFieldMap();
        while(field != null){
            if(field.getBoolean(FieldMap.bool_PRIMARYKEY) == true){
                retval.add(field);
            }
            field = this.getNextFieldMap();
        }
        this.index = savedindex;
        return retval;
    }

    @SuppressWarnings("unchecked")
	public Vector<String> getM_log() {
        return this.getParent().getM_log();
    }
}
